#include "stdafx.h"
#include "3DArcBallCam.h"
#include "glu.h"
#include "Vector2f.h"
#include "Vector3f.h"
#include <cmath>

vector3f X_AXIS(1.0f, 0.0f, 0.0f);
vector3f Y_AXIS(0.0f, 1.0f, 0.0f);
vector3f Z_AXIS(0.0f, 0.0f, 1.0f);

//-------------------------------------------------------------------------
// constructors
//-------------------------------------------------------------------------

C3DArcBallCam::C3DArcBallCam()
{
	m_mRotation.UnitRotationMatrix();
}

//-------------------------------------------------------------------------
// functions
//-------------------------------------------------------------------------

void C3DArcBallCam::MoveCam()
{
	// +Y is UP vector (standard OpenGL right-hand coordinate system)

	gluLookAt(m_vCamPos.x, m_vCamPos.y, m_vCamPos.z, m_vLensPos.x, m_vLensPos.y, m_vLensPos.z, 0.0f, 1.0f, 0.0f);

	// Compute rotation matrix from rotation quaternion

	m_qCamera.QuatToRotationMatrix(m_mRotation);

	// Apply rotation matrix

	glMultMatrixf(m_mRotation.m);
}

void C3DArcBallCam::ApplyQuaternionRotationFromMouse(vector2f vFrom, vector2f vTo)
{
	// Project the mouse positions on sphere

	vector3f vFromPos = MapCursorPositionOnSphere(vFrom.x, vFrom.y);
	vector3f vToPos = MapCursorPositionOnSphere(vTo.x, vTo.y);

	// Set quaternion vector to the cross product of the vectors

	m_qRotation.v = CrossProduct(vToPos, vFromPos); // order is important!

	// Set quaternion scalar to dot product of the vectors

	m_qRotation.w = DotProduct(vToPos, vFromPos);

	// Apply the rotation quaternion

	m_qCamera *= m_qRotation;
}

vector3f C3DArcBallCam::MapCursorPositionOnSphere(float x, float y)
{

	vector3f v;
	v.x = x;
	v.y = y;

    float fMag = v.x*v.x + v.y*v.y;

    if (fMag > 1.0f) 
	{
		float fScale = 1.0f / sqrtf(fMag);
		v.x *= fScale; 
		v.y *= fScale; 
		v.z = 0.0f; 
    } 
	else 
	{
		v.z = sqrtf(1.0f - fMag);
    }

	return v;
}

void C3DArcBallCam::ZoomIn()
{
	m_vCamPos.y -= 1.0f;
	m_vCamPos.z -= 1.0f;

	if (m_vCamPos.y < 1.0f) m_vCamPos.y = 1.0f;
	if (m_vCamPos.z < 1.0f) m_vCamPos.z = 1.0f;

}

void C3DArcBallCam::ZoomOut()
{
	m_vCamPos.y += 1.0f;
	m_vCamPos.z += 1.0f;
}

void C3DArcBallCam::ApplyQuaternionRotationFromKeypad(UINT nChar, float fRotationAngle)
{
	CQuaternion qKeypad;

	switch(nChar)
	{
		case VK_UP:
		case VK_NUMPAD8:
			qKeypad.AngleAxisToQuat(X_AXIS, fRotationAngle);
			qKeypad.Normalize();
			m_qCamera *= qKeypad;
			break;
		case VK_DOWN:
		case VK_NUMPAD2:
			qKeypad.AngleAxisToQuat(X_AXIS, -fRotationAngle);
			qKeypad.Normalize();
			m_qCamera *= qKeypad;
			break;
		case VK_RIGHT:
		case VK_NUMPAD6:
			qKeypad.AngleAxisToQuat(Y_AXIS, -fRotationAngle);
			qKeypad.Normalize();
			m_qCamera *= qKeypad;
			break;
		case VK_LEFT:
		case VK_NUMPAD4:
			qKeypad.AngleAxisToQuat(Y_AXIS, fRotationAngle);
			qKeypad.Normalize();
			m_qCamera *= qKeypad;
			break;
		case VK_PRIOR:
		case VK_NUMPAD9:
			qKeypad.AngleAxisToQuat(Z_AXIS, fRotationAngle);
			qKeypad.Normalize();
			m_qCamera *= qKeypad;
			break;
		case VK_HOME:
		case VK_NUMPAD7:
			qKeypad.AngleAxisToQuat(Z_AXIS, -fRotationAngle);
			qKeypad.Normalize();
			m_qCamera *= qKeypad;
			break;
		case VK_DELETE:
		case VK_NUMPAD5:
			qKeypad.AngleAxisToQuat(X_AXIS, 0.0f);
			qKeypad.Normalize();
			m_qCamera = qKeypad;
			break;
	};
}